package com.google.code.jira.script.workflow;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;

import org.apache.log4j.Category;
import org.ofbiz.core.util.UtilMisc;

import com.atlassian.jira.plugin.workflow.AbstractWorkflowPluginFactory;
import com.atlassian.jira.plugin.workflow.WorkflowPluginConditionFactory;
import com.atlassian.jira.plugin.workflow.WorkflowPluginFunctionFactory;
import com.atlassian.jira.plugin.workflow.WorkflowPluginValidatorFactory;
import com.opensymphony.workflow.loader.AbstractDescriptor;
import com.opensymphony.workflow.loader.ConditionDescriptor;
import com.opensymphony.workflow.loader.FunctionDescriptor;
import com.opensymphony.workflow.loader.ValidatorDescriptor;

public class ScriptConfigurationFactory extends AbstractWorkflowPluginFactory implements
		WorkflowPluginConditionFactory, WorkflowPluginFunctionFactory, WorkflowPluginValidatorFactory {

	private static final Category log = Category.getInstance(ScriptConfigurationFactory.class);

	private final List engines = new ArrayList();

	public ScriptConfigurationFactory() {
		List engineFactories = new ScriptEngineManager().getEngineFactories();
		if (engineFactories == null || engineFactories.size() == 0) {
			log.warn("No script engine found!");
		}

		Iterator iterator = engineFactories.iterator();
		while (iterator.hasNext()) {
			ScriptEngineFactory factory = (ScriptEngineFactory) iterator.next();
			engines.add(factory.getEngineName());
		}
	}

	protected void getVelocityParamsForInput(Map velocityParams) {
		getVelocityParamsForEdit(velocityParams, null);
	}

	protected void getVelocityParamsForEdit(Map velocityParams, AbstractDescriptor descriptor) {
		velocityParams.put("engines", engines);

		// Sets empty values to the expected params for input.
		if (descriptor == null) {
			velocityParams.put(ScriptWorkflowUtils.SCRIPT_NAME, "");
			velocityParams.put(ScriptWorkflowUtils.ENGINE_NAME, "");
			velocityParams
					.put(
							ScriptWorkflowUtils.SCRIPT_CONTENT,
							"// Objects available:\n"
									+ "// issue (a mutable issue object)\n"
									+ "// originalissue (an inmutable issue object that represents the original issue holding unmodified values)\n"
									+ "// caller (an user object that represents the user that is currently logged in and executing the workflow transition)\n"
									+ "// log (a log object which can be used to print messages using the log engine)\n");
			return;
		}

		// Sets the selected values to expected params for edit.
		Map args = null;
		if (descriptor instanceof ConditionDescriptor) {
			args = ((ConditionDescriptor) descriptor).getArgs();
		} else if (descriptor instanceof ValidatorDescriptor) {
			args = ((ValidatorDescriptor) descriptor).getArgs();
		} else if (descriptor instanceof FunctionDescriptor) {
			args = ((FunctionDescriptor) descriptor).getArgs();
		}

		velocityParams.put(ScriptWorkflowUtils.SCRIPT_NAME, ScriptWorkflowUtils.getScriptName(args));
		velocityParams.put(ScriptWorkflowUtils.ENGINE_NAME, ScriptWorkflowUtils.getEngineName(args));
		velocityParams.put(ScriptWorkflowUtils.SCRIPT_CONTENT, ScriptWorkflowUtils.getScriptContent(args));
	}

	protected void getVelocityParamsForView(Map velocityParams, AbstractDescriptor descriptor) {
		getVelocityParamsForEdit(velocityParams, descriptor);
	}

	public Map getDescriptorParams(Map descriptorParams) {
		String scriptName = extractSingleParam(descriptorParams, ScriptWorkflowUtils.SCRIPT_NAME);
		String engineName = extractSingleParam(descriptorParams, ScriptWorkflowUtils.ENGINE_NAME);
		String scriptContent = extractSingleParam(descriptorParams, ScriptWorkflowUtils.SCRIPT_CONTENT);

		return UtilMisc.toMap(ScriptWorkflowUtils.SCRIPT_NAME, scriptName, ScriptWorkflowUtils.ENGINE_NAME, engineName,
				ScriptWorkflowUtils.SCRIPT_CONTENT, scriptContent);
	}
}